IDENTIFY MACRO-AREAS OR MARKET FIELDS within the database to acquire some general awareness on its content

library(tidyverse)

data <- read_csv("../../data/data_subset1.csv")

names(data)
library(skimr)
#skim(data)

Wordcloud

Codice da: Using tidytext to make word clouds (richpauloo.github.io)

library(dplyr) # for data wrangling
library(tidytext) # for NLP
library(stringr) # to deal with strings
library(wordcloud) # to render wordclouds
library(knitr) # for tables
library(DT) # for dynamic tables
library(tidyr)

tidy_dat <- tidyr::gather(data %>%
                            unite(col="united", abstract, title, sep=" ") %>%
                            select(united), key, word) %>% select(word)

tidy_dat
library(SnowballC)

#uso lo stemming perchè il lemming (udpipe_annotate) sarebbe troppo lento ad eseguire
tokens <- tidy_dat %>% 
  unnest_tokens(word, word) %>% 
  mutate(word = wordStem(word)) %>% 
  dplyr::count(word, sort = TRUE) %>% 
  ungroup()

data("stop_words")
tokens_clean <- tokens %>%
  anti_join(stop_words)

nums <- tokens_clean %>% filter(str_detect(word, "^[0-9]")) %>% select(word) %>% unique()

tokens_clean <- tokens_clean %>% 
  anti_join(nums, by = "word")

tokens_clean %>% head(100)
pal <- brewer.pal(8,"Dark2")

tokens_clean %>% 
  with(wordcloud(word, n, random.order = FALSE, max.words = 50, colors=pal))
uni_sw <- data.frame(word = c("claim", "based", "model",
                              "data", "invetion", "network",
                              "methods", "dataset",
                              "l3", "computer", "computing",
                              "device", "plurality",
                              "comprising", "word",
                              "user",
                              "based",
                              "comprises",
                              "system",
                              "image",
                              "model",
                              "processor",
                              "process",
                              "sentence",
                              "workload",
                              "method",
                              "data",
                              "system"
                              ))

tokens_clean <- tokens_clean %>% 
  anti_join(uni_sw, by = "word")
pal <- brewer.pal(8,"Dark2")

tokens_clean %>% 
  with(wordcloud(word, n, random.order = FALSE, max.words = 50, colors=pal))

Topic modeling

Codice da: Topic modeling | Text Mining with R (tidytextmining.com)

library(topicmodels)
data %>%
  group_by(filename)
data_word_count = data %>%
  select(filename, abstract, claims, title) %>%
  unite(col="united", abstract, title, sep=" ") %>%
  unnest_tokens(word, united) %>%
  mutate(word = wordStem(word)) %>% 
  count(filename, word, sort = TRUE) %>%
  anti_join(stop_words)

data_word_count %>% head(10)
data_dtm <- data_word_count %>%
  cast_dtm(filename, word, n)

data_dtm
data_lda <- LDA(data_dtm, k = 16, control = list(seed = 1234))
library(reshape2)

ap_topics <- tidy(data_lda, matrix = "beta")

ap_topics
ap_top_terms <- ap_topics %>%
  group_by(topic) %>%
  slice_max(beta, n = 7) %>% 
  ungroup() %>%
  arrange(topic, -beta)

ap_gg = ap_top_terms %>%
  mutate(term = reorder_within(term, beta, topic)) %>%
  ggplot(aes(beta, term, fill = factor(topic))) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  scale_y_reordered()


ap_gg


beta_wide <- ap_topics %>%
  mutate(topic = paste0("topic", topic)) %>%
  pivot_wider(names_from = topic, values_from = beta) %>% 
  filter(topic1 > .001 | topic2 > .001) %>%
  mutate(log_ratio = log2(topic2 / topic1))

beta_wide

Bigrams

codice da Relationships between words: n-grams and correlations | Text Mining with R (tidytextmining.com)

bigrams <- data %>%
  unite(col="united", title, sep=" ") %>%
  unnest_tokens(bigram, united, token = "ngrams", n = 2) %>%
  select(bigram) #%>%
  #count(bigram, sort=TRUE)

bigrams
bigrams_separated <- bigrams %>%
  separate(bigram, c("word1", "word2"), sep = " ")

bigrams_filtered <- bigrams_separated %>%
  filter(!word1 %in% stop_words$word) %>%
  filter(!word2 %in% stop_words$word) %>%
  filter(!str_detect(word1, "^[0-9]")) %>%
  filter(!str_detect(word2, "^[0-9]"))

# new bigram counts:
bigram_counts <- bigrams_filtered %>% 
  mutate(word1 = wordStem(word1)) %>% 
  mutate(word2 = wordStem(word2)) %>% 
  count(word1, word2, sort = TRUE)

bigram_counts
library(igraph)
library(ggraph)

bigram_graph <- bigram_counts %>%
  filter(n >= 500) %>%
  graph_from_data_frame()

set.seed(2017)

gg <- ggraph(bigram_graph, layout = "fr") + #fr o graphopt
  geom_edge_link() +
  geom_node_point() +
  geom_node_text(aes(label = name),  hjust = 1, vjust=1) +
  theme_void()

gg

library(igraph)
library(ggiraph)

gg

Using CPC

codice sunburst da: Create Basic Sunburst Graphs with ggplot2 | by Yahia El Gamal | Optima . Blog | Medium

library(tidyverse)

cpc_descr <- read_csv("../../data/CPC_descriptions.csv")
Rows: 259657 Columns: 8
-- Column specification ----------------------------------------------
Delimiter: ","
chr (8): code_1, code_3, code_4, code_full, descr_1, descr_3, desc...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
cpc_descr %>% head(5)
data %>% head(5)
data %>% mutate(tmp = substr(ipc_classes[1], 0, 3))
data %>% 
  mutate(code_4 = tolower(substr(ipc_classes, 0, 4))) %>%
  inner_join(cpc_descr 
             %>% select(code_4, descr_1, descr_3, descr_4) %>% 
                distinct(),
             by="code_4"
             ) -> res

res %>% head()
res <- res %>%
  select(filename, descr_1, descr_3, descr_4) %>%
  count(filename, descr_1, descr_3, descr_4, sort = TRUE)

res
library(sunburstR)
res$descr_1<-gsub("-","_",as.character(res$descr_1))
res$descr_3<-gsub("-","_",as.character(res$descr_3))
res$descr_4<-gsub("-","_",as.character(res$descr_4))

dat <- res %>% 
  unite(col="united", descr_1, descr_3, descr_4, sep="-") %>%
  group_by(united) %>%
  count(sort= TRUE)

dat %>% head()
library(d3r)
  

sb3 <- sund2b(dat,
              breadcrumbs = sund2bBreadcrumb(enabled = TRUE), 
              showLabels=TRUE)

sb3
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJREVOVElGWSBNQUNSTy1BUkVBUyBPUiBNQVJLRVQgRklFTERTIHdpdGhpbiB0aGUgZGF0YWJhc2UgdG8gYWNxdWlyZSBzb21lIGdlbmVyYWwgYXdhcmVuZXNzIG9uIGl0cyBjb250ZW50DQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCmRhdGEgPC0gcmVhZF9jc3YoIi4uLy4uL2RhdGEvZGF0YV9zdWJzZXQxLmNzdiIpDQoNCm5hbWVzKGRhdGEpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNraW1yKQ0KI3NraW0oZGF0YSkNCmBgYA0KDQojIyBXb3JkY2xvdWQNCg0KQ29kaWNlIGRhOiBbVXNpbmcgdGlkeXRleHQgdG8gbWFrZSB3b3JkIGNsb3VkcyAocmljaHBhdWxvby5naXRodWIuaW8pXShodHRwczovL3JpY2hwYXVsb28uZ2l0aHViLmlvLzIwMTctMTItMjktVXNpbmctdGlkeXRleHQtdG8tbWFrZS13b3JkLWNsb3Vkcy8pDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikgIyBmb3IgZGF0YSB3cmFuZ2xpbmcNCmxpYnJhcnkodGlkeXRleHQpICMgZm9yIE5MUA0KbGlicmFyeShzdHJpbmdyKSAjIHRvIGRlYWwgd2l0aCBzdHJpbmdzDQpsaWJyYXJ5KHdvcmRjbG91ZCkgIyB0byByZW5kZXIgd29yZGNsb3Vkcw0KbGlicmFyeShrbml0cikgIyBmb3IgdGFibGVzDQpsaWJyYXJ5KERUKSAjIGZvciBkeW5hbWljIHRhYmxlcw0KbGlicmFyeSh0aWR5cikNCg0KdGlkeV9kYXQgPC0gdGlkeXI6OmdhdGhlcihkYXRhICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXRlKGNvbD0idW5pdGVkIiwgYWJzdHJhY3QsIHRpdGxlLCBzZXA9IiAiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QodW5pdGVkKSwga2V5LCB3b3JkKSAlPiUgc2VsZWN0KHdvcmQpDQoNCnRpZHlfZGF0DQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoU25vd2JhbGxDKQ0KDQojdXNvIGxvIHN0ZW1taW5nIHBlcmNow6ggaWwgbGVtbWluZyAodWRwaXBlX2Fubm90YXRlKSBzYXJlYmJlIHRyb3BwbyBsZW50byBhZCBlc2VndWlyZQ0KdG9rZW5zIDwtIHRpZHlfZGF0ICU+JSANCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB3b3JkKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gd29yZFN0ZW0od29yZCkpICU+JSANCiAgZHBseXI6OmNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpkYXRhKCJzdG9wX3dvcmRzIikNCnRva2Vuc19jbGVhbiA8LSB0b2tlbnMgJT4lDQogIGFudGlfam9pbihzdG9wX3dvcmRzKQ0KDQpudW1zIDwtIHRva2Vuc19jbGVhbiAlPiUgZmlsdGVyKHN0cl9kZXRlY3Qod29yZCwgIl5bMC05XSIpKSAlPiUgc2VsZWN0KHdvcmQpICU+JSB1bmlxdWUoKQ0KDQp0b2tlbnNfY2xlYW4gPC0gdG9rZW5zX2NsZWFuICU+JSANCiAgYW50aV9qb2luKG51bXMsIGJ5ID0gIndvcmQiKQ0KDQp0b2tlbnNfY2xlYW4gJT4lIGhlYWQoMTAwKQ0KDQpgYGANCg0KYGBge3J9DQpwYWwgPC0gYnJld2VyLnBhbCg4LCJEYXJrMiIpDQoNCnRva2Vuc19jbGVhbiAlPiUgDQogIHdpdGgod29yZGNsb3VkKHdvcmQsIG4sIHJhbmRvbS5vcmRlciA9IEZBTFNFLCBtYXgud29yZHMgPSA1MCwgY29sb3JzPXBhbCkpDQpgYGANCg0KYGBge3J9DQp1bmlfc3cgPC0gZGF0YS5mcmFtZSh3b3JkID0gYygiY2xhaW0iLCAiYmFzZWQiLCAibW9kZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGEiLCAiaW52ZXRpb24iLCAibmV0d29yayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWV0aG9kcyIsICJkYXRhc2V0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsMyIsICJjb21wdXRlciIsICJjb21wdXRpbmciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRldmljZSIsICJwbHVyYWxpdHkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXByaXNpbmciLCAid29yZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidXNlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbXByaXNlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3lzdGVtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbWFnZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW9kZWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByb2Nlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJvY2VzcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VudGVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndvcmtsb2FkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtZXRob2QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhdGEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN5c3RlbSINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQoNCnRva2Vuc19jbGVhbiA8LSB0b2tlbnNfY2xlYW4gJT4lIA0KICBhbnRpX2pvaW4odW5pX3N3LCBieSA9ICJ3b3JkIikNCg0KYGBgDQoNCmBgYHtyfQ0KcGFsIDwtIGJyZXdlci5wYWwoOCwiRGFyazIiKQ0KDQp0b2tlbnNfY2xlYW4gJT4lIA0KICB3aXRoKHdvcmRjbG91ZCh3b3JkLCBuLCByYW5kb20ub3JkZXIgPSBGQUxTRSwgbWF4LndvcmRzID0gNTAsIGNvbG9ycz1wYWwpKQ0KDQoNCmBgYA0KDQojIyBUb3BpYyBtb2RlbGluZw0KDQpDb2RpY2UgZGE6IFtUb3BpYyBtb2RlbGluZyBcfCBUZXh0IE1pbmluZyB3aXRoIFIgKHRpZHl0ZXh0bWluaW5nLmNvbSldKGh0dHBzOi8vd3d3LnRpZHl0ZXh0bWluaW5nLmNvbS90b3BpY21vZGVsaW5nLmh0bWwpDQoNCmBgYHtyfQ0KbGlicmFyeSh0b3BpY21vZGVscykNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lDQogIGdyb3VwX2J5KGZpbGVuYW1lKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV93b3JkX2NvdW50ID0gZGF0YSAlPiUNCiAgc2VsZWN0KGZpbGVuYW1lLCBhYnN0cmFjdCwgY2xhaW1zLCB0aXRsZSkgJT4lDQogIHVuaXRlKGNvbD0idW5pdGVkIiwgYWJzdHJhY3QsIHRpdGxlLCBzZXA9IiAiKSAlPiUNCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB1bml0ZWQpICU+JQ0KICBtdXRhdGUod29yZCA9IHdvcmRTdGVtKHdvcmQpKSAlPiUgDQogIGNvdW50KGZpbGVuYW1lLCB3b3JkLCBzb3J0ID0gVFJVRSkgJT4lDQogIGFudGlfam9pbihzdG9wX3dvcmRzKQ0KDQpkYXRhX3dvcmRfY291bnQgJT4lIGhlYWQoMTApDQpgYGANCg0KYGBge3J9DQpkYXRhX2R0bSA8LSBkYXRhX3dvcmRfY291bnQgJT4lDQogIGNhc3RfZHRtKGZpbGVuYW1lLCB3b3JkLCBuKQ0KDQpkYXRhX2R0bQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9sZGEgPC0gTERBKGRhdGFfZHRtLCBrID0gMTYsIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAxMjM0KSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocmVzaGFwZTIpDQoNCmFwX3RvcGljcyA8LSB0aWR5KGRhdGFfbGRhLCBtYXRyaXggPSAiYmV0YSIpDQoNCmFwX3RvcGljcw0KYGBgDQoNCmBgYHtyfQ0KYXBfdG9wX3Rlcm1zIDwtIGFwX3RvcGljcyAlPiUNCiAgZ3JvdXBfYnkodG9waWMpICU+JQ0KICBzbGljZV9tYXgoYmV0YSwgbiA9IDcpICU+JSANCiAgdW5ncm91cCgpICU+JQ0KICBhcnJhbmdlKHRvcGljLCAtYmV0YSkNCg0KYXBfZ2cgPSBhcF90b3BfdGVybXMgJT4lDQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcl93aXRoaW4odGVybSwgYmV0YSwgdG9waWMpKSAlPiUNCiAgZ2dwbG90KGFlcyhiZXRhLCB0ZXJtLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBmYWNldF93cmFwKH4gdG9waWMsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBzY2FsZV95X3Jlb3JkZXJlZCgpDQoNCg0KYXBfZ2cNCg0KYGBgDQoNClwNCg0KYGBge3J9DQpiZXRhX3dpZGUgPC0gYXBfdG9waWNzICU+JQ0KICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoInRvcGljIiwgdG9waWMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRvcGljLCB2YWx1ZXNfZnJvbSA9IGJldGEpICU+JSANCiAgZmlsdGVyKHRvcGljMSA+IC4wMDEgfCB0b3BpYzIgPiAuMDAxKSAlPiUNCiAgbXV0YXRlKGxvZ19yYXRpbyA9IGxvZzIodG9waWMyIC8gdG9waWMxKSkNCg0KYmV0YV93aWRlDQpgYGANCg0KIyMgQmlncmFtcw0KDQpjb2RpY2UgZGEgW1JlbGF0aW9uc2hpcHMgYmV0d2VlbiB3b3Jkczogbi1ncmFtcyBhbmQgY29ycmVsYXRpb25zIFx8IFRleHQgTWluaW5nIHdpdGggUiAodGlkeXRleHRtaW5pbmcuY29tKV0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL25ncmFtcy5odG1sKQ0KDQpgYGB7cn0NCmJpZ3JhbXMgPC0gZGF0YSAlPiUNCiAgdW5pdGUoY29sPSJ1bml0ZWQiLCB0aXRsZSwgc2VwPSIgIikgJT4lDQogIHVubmVzdF90b2tlbnMoYmlncmFtLCB1bml0ZWQsIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAlPiUNCiAgc2VsZWN0KGJpZ3JhbSkgIyU+JQ0KICAjY291bnQoYmlncmFtLCBzb3J0PVRSVUUpDQoNCmJpZ3JhbXMNCmBgYA0KDQpgYGB7cn0NCmJpZ3JhbXNfc2VwYXJhdGVkIDwtIGJpZ3JhbXMgJT4lDQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKQ0KDQpiaWdyYW1zX2ZpbHRlcmVkIDwtIGJpZ3JhbXNfc2VwYXJhdGVkICU+JQ0KICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcF93b3JkcyR3b3JkKSAlPiUNCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lDQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkMSwgIl5bMC05XSIpKSAlPiUNCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQyLCAiXlswLTldIikpDQoNCiMgbmV3IGJpZ3JhbSBjb3VudHM6DQpiaWdyYW1fY291bnRzIDwtIGJpZ3JhbXNfZmlsdGVyZWQgJT4lIA0KICBtdXRhdGUod29yZDEgPSB3b3JkU3RlbSh3b3JkMSkpICU+JSANCiAgbXV0YXRlKHdvcmQyID0gd29yZFN0ZW0od29yZDIpKSAlPiUgDQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpDQoNCmJpZ3JhbV9jb3VudHMNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoaWdyYXBoKQ0KbGlicmFyeShnZ3JhcGgpDQoNCmJpZ3JhbV9ncmFwaCA8LSBiaWdyYW1fY291bnRzICU+JQ0KICBmaWx0ZXIobiA+PSA1MDApICU+JQ0KICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKQ0KDQpzZXQuc2VlZCgyMDE3KQ0KDQpnZyA8LSBnZ3JhcGgoYmlncmFtX2dyYXBoLCBsYXlvdXQgPSAiZnIiKSArICNmciBvIGdyYXBob3B0DQogIGdlb21fZWRnZV9saW5rKCkgKw0KICBnZW9tX25vZGVfcG9pbnQoKSArDQogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCAgaGp1c3QgPSAxLCB2anVzdD0xKSArDQogIHRoZW1lX3ZvaWQoKQ0KDQpnZw0KYGBgDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkoZ2dpcmFwaCkNCg0KZ2cNCmBgYA0KDQojIyMgVXNpbmcgQ1BDDQoNCmNvZGljZSBzdW5idXJzdCBkYTogW0NyZWF0ZSBCYXNpYyBTdW5idXJzdCBHcmFwaHMgd2l0aCBnZ3Bsb3QyIFx8IGJ5IFlhaGlhIEVsIEdhbWFsIFx8IE9wdGltYSAuIEJsb2cgXHwgTWVkaXVtXShodHRwczovL21lZGl1bS5jb20vb3B0aW1hLWJsb2cvY3JlYXRlLWJhc2ljLXN1bmJ1cnN0LWdyYXBocy13aXRoLWdncGxvdDItN2Q3NDg0ZDkyYzYxKQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpjcGNfZGVzY3IgPC0gcmVhZF9jc3YoIi4uLy4uL2RhdGEvQ1BDX2Rlc2NyaXB0aW9ucy5jc3YiKQ0KDQpjcGNfZGVzY3IgJT4lIGhlYWQoNSkNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lIGhlYWQoNSkNCmBgYA0KDQpgYGB7cn0NCmRhdGEgJT4lIG11dGF0ZSh0bXAgPSBzdWJzdHIoaXBjX2NsYXNzZXNbMV0sIDAsIDMpKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YSAlPiUgDQogIG11dGF0ZShjb2RlXzQgPSB0b2xvd2VyKHN1YnN0cihpcGNfY2xhc3NlcywgMCwgNCkpKSAlPiUNCiAgaW5uZXJfam9pbihjcGNfZGVzY3IgDQogICAgICAgICAgICAgJT4lIHNlbGVjdChjb2RlXzQsIGRlc2NyXzEsIGRlc2NyXzMsIGRlc2NyXzQpICU+JSANCiAgICAgICAgICAgICAgICBkaXN0aW5jdCgpLA0KICAgICAgICAgICAgIGJ5PSJjb2RlXzQiDQogICAgICAgICAgICAgKSAtPiByZXMNCg0KcmVzICU+JSBoZWFkKCkNCmBgYA0KDQpgYGB7cn0NCnJlcyA8LSByZXMgJT4lDQogIHNlbGVjdChmaWxlbmFtZSwgZGVzY3JfMSwgZGVzY3JfMywgZGVzY3JfNCkgJT4lDQogIGNvdW50KGZpbGVuYW1lLCBkZXNjcl8xLCBkZXNjcl8zLCBkZXNjcl80LCBzb3J0ID0gVFJVRSkNCg0KcmVzDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHN1bmJ1cnN0UikNCnJlcyRkZXNjcl8xPC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl8xKSkNCnJlcyRkZXNjcl8zPC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl8zKSkNCnJlcyRkZXNjcl80PC1nc3ViKCItIiwiXyIsYXMuY2hhcmFjdGVyKHJlcyRkZXNjcl80KSkNCg0KZGF0IDwtIHJlcyAlPiUgDQogIHVuaXRlKGNvbD0idW5pdGVkIiwgZGVzY3JfMSwgZGVzY3JfMywgZGVzY3JfNCwgc2VwPSItIikgJT4lDQogIGdyb3VwX2J5KHVuaXRlZCkgJT4lDQogIGNvdW50KHNvcnQ9IFRSVUUpDQoNCmRhdCAlPiUgaGVhZCgpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGQzcikNCiAgDQoNCnNiMyA8LSBzdW5kMmIoZGF0LA0KICAgICAgICAgICAgICBicmVhZGNydW1icyA9IHN1bmQyYkJyZWFkY3J1bWIoZW5hYmxlZCA9IFRSVUUpLCANCiAgICAgICAgICAgICAgc2hvd0xhYmVscz1UUlVFKQ0KDQpzYjMNCmBgYA0K